package aop.test.advice;

import cn.stimd.spring.aop.AfterReturningAdvice;
import cn.stimd.spring.aop.MethodBeforeAdvice;
import cn.stimd.spring.aop.ThrowsAdvice;
import cn.stimd.spring.aop.framework.adapter.AfterReturningAdviceInterceptor;
import cn.stimd.spring.aop.framework.adapter.MethodBeforeAdviceInterceptor;
import cn.stimd.spring.aop.framework.adapter.ThrowsAdviceInterceptor;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Stimd
 * 项目地址：https://gitee.com/stimd/spring-wheel
 * 公众号：Java编程探微
 */
public class AdviceSupport {
    private List<MethodInterceptor> interceptors = new ArrayList<>();
    private Object target;


    //添加通知
    public void addAdvice(Advice advice){
        MethodInterceptor interceptor = null;
        //前置通知
        if(advice instanceof MethodBeforeAdvice){
            interceptor = new MethodBeforeAdviceInterceptor((MethodBeforeAdvice) advice);
        }
        //返回通知
        else if (advice instanceof AfterReturningAdvice){
            interceptor = new AfterReturningAdviceInterceptor((AfterReturningAdvice) advice);
        }
        //异常通知
        else if (advice instanceof ThrowsAdvice){
            interceptor = new ThrowsAdviceInterceptor(advice);
        }
        this.interceptors.add(interceptor);
    }


    //调用目标对象的方法
    public void invoke(String methodName) throws Throwable {
        Method targetMethod = null;
        //通过反射的方式寻找目标方法
        for (Method method : this.target.getClass().getDeclaredMethods()) {
            if(method.getName().equals(methodName)){
                targetMethod = method;
                break;
            }
        }

        //将Method包装成一个方法调用，执行增强逻辑和目标方法
        if(targetMethod != null){
            SimpleMethodInvocation mi = new SimpleMethodInvocation(targetMethod, this.target, this.interceptors);
            mi.proceed();
        }
    }


    public void addInterceptor(MethodInterceptor interceptor) {
        this.interceptors.add(interceptor);
    }

    public void setTarget(Object target){
        this.target = target;
    }
}
